package constantHeader

import (
	"errors"
	"gitee.com/squbirreland/imgo/mqtt/constant"
	"gitee.com/squbirreland/imgo/utils/byteMath"
	"log"
)

type ConstantHeader struct {
	//--固定报头 ConstantHeader
	/*
		Control 控制位
		半个byte
		其表示了消息的发送类型 根据控制位会影响可变报头和载荷
	*/
	Control constant.ControlBit4

	/*
		Zone 标志位
		半个byte
		标志位占用半个byte也就是4个bit
		其1表示是否保存
		其23表示qos等级
		其4表示是否重复
	*/
	Zone constant.ZoneBit4

	/*
		OverLength 剩余长度
		1~4个byte
		包含了可变报头和有效载荷的长度
	*/
	OverLength int64

	headerLength int
	headerBytes  []byte
}

func NewConstantHeader(control constant.ControlBit4, zone constant.ZoneBit4, overLength int64) *ConstantHeader {
	return &ConstantHeader{Control: control, Zone: zone, OverLength: overLength}
}

func NewConstantHeaderByBytes(b []byte) *ConstantHeader {
	return &ConstantHeader{headerBytes: b}
}

func (c *ConstantHeader) Parse() error {
	if c.headerBytes == nil || len(c.headerBytes) == 0 {
		return errors.New(" no header bytes set in !")
	}
	//将byte[0]转为2进制
	str, err := byteMath.Byte2Str(c.headerBytes[0], 2, 8)
	if err != nil {
		return err
	}
	//切分该二进制byte的一半 解析控制位
	controlBit4Str := str[:4]
	control, err := byteMath.Str2Int(controlBit4Str, 2)
	if err != nil {
		return err
	}
	c.Control = constant.ControlBit4(control)
	//切分该二进制byte的后一般 解析标志位
	zoneBit4Str := str[4:]
	dup := false
	if zoneBit4Str[0] == '1' {
		dup = true
	}
	retain := false
	if zoneBit4Str[3] == '1' {
		retain = true
	}
	qosInt, err := byteMath.Str2Int(zoneBit4Str[1:3], 2)
	if err != nil {
		return err
	}
	c.Zone = constant.ZoneBit4{
		RETAIN: retain,
		DUP:    dup,
		QOS:    constant.QOSBit2(qosInt),
	}
	//计算动态的剩余长度
	if c.headerBytes[1] > 0x7f {
		//base1 min 0 max 127
		c.OverLength = int64(c.headerBytes[1]) - 0x80
		if c.headerBytes[2] > 0x7f {
			//base2 min 0 max 16256
			c.OverLength += int64(c.headerBytes[2]-0x80) * 0x80
			if c.headerBytes[3] > 0x7f {
				//2097152~268435455
				//base4 min 2097152 max 266338304
				//base3 min 0 max 2080768
				c.OverLength += int64(c.headerBytes[3]-0x80)*0x80*0x80 + int64(c.headerBytes[4])*0x80*0x80*0x80
				c.headerLength = 5
			} else {
				//16384~2097151
				//base3 min 16384 max 2080768
				c.OverLength += int64(c.headerBytes[3]) * 0x80 * 0x80
				c.headerLength = 4
			}
		} else {
			//128~16383
			//base2 min 128 max 16256
			c.OverLength += int64(c.headerBytes[2]) * 0x80
			c.headerLength = 3
		}
	} else {
		//0~127
		c.OverLength = int64(c.headerBytes[1])
		c.headerLength = 2
	}
	c.headerBytes = c.headerBytes[:c.headerLength]
	return nil
}

func (c *ConstantHeader) GenerateBytes() error {
	//控制位
	controlStr, err := byteMath.Int2Str(int(c.Control), 2, 4)
	if err != nil {
		return err
	}
	//标志位
	zoneStr := ""
	if c.Zone.DUP {
		zoneStr = zoneStr + "1"
	} else {
		zoneStr = zoneStr + "0"
	}
	qosStr, err := byteMath.Int2Str(int(c.Zone.QOS), 2, 2)
	if err != nil {
		return err
	}
	zoneStr = zoneStr + qosStr
	if c.Zone.RETAIN {
		zoneStr = zoneStr + "1"
	} else {
		zoneStr = zoneStr + "0"
	}
	b1, err := byteMath.Str2Byte(controlStr+zoneStr, 2)
	if err != nil {
		return nil
	}
	b := make([]byte, 0, 10)
	//加入第一个byte
	b = append(b, b1)
	//剩余长度
	overLength := make([]byte, 0, 4)
	if c.OverLength > 127 {
		overLength = append(overLength, byte(c.OverLength%(128)+128))
		if c.OverLength > 16383 {
			overLength = append(overLength, byte(c.OverLength%(128*128)+128))
			if c.OverLength > 2097151 {
				if c.OverLength > 268435455 {
					log.Println(" over length too long : ", c.OverLength)
				} else {
					//2097152~268435455
					overLength = append(overLength, byte(c.OverLength%(128*128*128)+128), byte(c.OverLength/(128*128*128)))
				}
			} else {
				//16384~2097151
				overLength = append(overLength, byte(c.OverLength/(128*128)))
			}
		} else {
			//128~16383
			byte1 := c.OverLength / 128
			overLength = append(overLength, byte(byte1))
		}
	} else {
		//0~127
		overLength = append(overLength, byte(c.OverLength))
	}
	b = append(b, overLength...)
	c.headerBytes = b
	return nil
}

func (c *ConstantHeader) GetLength() int {
	return c.headerLength
}

func (c *ConstantHeader) GetHeaderBytes() []byte {
	return c.headerBytes
}

func (c *ConstantHeader) SetHeaderBytes(b []byte) {
	c.headerBytes = b
}
